package com.atguigu.gmall.common.config;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.entity.GmallCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author gsy
 * @date 2021年09月12日19:48
 * Description
 */
@Component
@Slf4j
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    //后置
    @PostConstruct  //在Bean初始化后执行
    public void MQProducerAckConfig(){
        rabbitTemplate.setReturnCallback(this);
        rabbitTemplate.setConfirmCallback(this);
    }
    //交换机应答 失败成功都应答
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack){
            //成功接受到消息
            log.info("交换机成功应答:"+cause);
        }else {
            log.error("交换机失败应答:"+cause);
            //重新发生消息
           retrySendMessage(correlationData);
        }

    }
    //重新发生消息
    private void retrySendMessage(CorrelationData correlationData) {
        GmallCorrelationData gmallCorrelationData = (GmallCorrelationData) correlationData;
        String exchange = gmallCorrelationData.getExchange();
        //重试次数
        String routingKey = gmallCorrelationData.getRoutingKey();
        Object message = gmallCorrelationData.getMessage();
        int retryCount = gmallCorrelationData.getRetryCount();
        //发送2次或3次 还不成功工作人员人为干预
        if (retryCount<2){
            retryCount++;
            gmallCorrelationData.setRetryCount(retryCount);
            //更新缓存中重试次数
            redisTemplate.opsForValue().set(gmallCorrelationData.getId(),JSONObject.toJSONString(gmallCorrelationData));
            rabbitTemplate.convertAndSend(exchange,routingKey,message,gmallCorrelationData);
            log.info("生产者重新发送消息:第"+retryCount+"次");
        }else {
            //人为干预  打印日志
            log.error("生产者重试"+retryCount+"次,发送依然失败");
        }


    }


    //队列应答 失败才应答
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.error("队列失败应答, 信息:"+message);
        log.error("队列失败应答,失败状态码:"+replyCode);
        log.error("队列失败应答,失败信息:"+replyText);
        log.error("队列失败应答,交换机:"+exchange);
        log.error("队列失败应答,routingkey:"+routingKey);

        //获取gmallCorrelationData的主键id
        String id = (String) message.getMessageProperties().getHeaders().get("spring_returned_message_correlation");
        //根据id获取缓存中的gmallCorrelationData对象
        String s = (String) redisTemplate.opsForValue().get(id);
        //System.out.println(id);
        GmallCorrelationData gmallCorrelationData = JSONObject.parseObject(s, GmallCorrelationData.class);
        //判断是否为基于插件的延迟消息
        if (gmallCorrelationData.isDelay()){
            log.info("本次消息是延迟消息，不重新发送");

            return;
        }
        retrySendMessage(gmallCorrelationData);
    }



}
